package logic.ceb;

import java.security.Key;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

import org.apache.commons.codec.binary.Base64;

public class AESCodec {

	// 密钥算法
	public static final String KEY_ALGORITHM = "AES";

	// 加解密算法/工作模式/填充方式,Java6.0支持PKCS5Padding填充方式,BouncyCastle支持PKCS7Padding填充方式

	public static final String CIPHER_ALGORITHM = "AES/ECB/PKCS5Padding";

	/**
	 * 
	 * 生成密钥
	 */

	public static String initkey() throws Exception {
		KeyGenerator kg = KeyGenerator.getInstance(KEY_ALGORITHM); // 实例化密钥生成器

		kg.init(128); // 初始化密钥生成器:AES要求密钥长度为128,192,256位

		SecretKey secretKey = kg.generateKey(); // 生成密钥

		return Base64.encodeBase64String(secretKey.getEncoded()); // 获取二进制密钥编码形式

	}

	/**
	 * 054 转换密钥 055
	 */

	public static Key toKey(byte[] key) throws Exception {
		return new SecretKeySpec(key, KEY_ALGORITHM);

	}

	public static byte[] decryptAESCBC128(byte[] raw, byte[] iv,
			byte[] encrypted) throws Exception {
		// AES/CBC/NoPadding
		// AES/CBC/PKCS5Padding
		// AES/CBC/ISO10126Padding
		// AES/ECB/pkcs5padding
		// AES/ECB/pkcs7padding
		Key k = toKey(Base64.decodeBase64(raw));
		// SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
		IvParameterSpec ivSpec = new IvParameterSpec(iv);
		Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
		cipher.init(Cipher.DECRYPT_MODE, k, ivSpec);
		byte[] decrypted = cipher.doFinal(encrypted);
		return decrypted;
	}

	/**
	 * 062 加密数据 063
	 * 
	 * @param data
	 *            待加密数据 064
	 * @param key
	 *            密钥 065
	 * @return 加密后的数据 066
	 * */

	public static String encrypt(String data, String key) throws Exception {

		Key k = toKey(Base64.decodeBase64(key)); // 还原密钥

		// 使用PKCS7Padding填充方式,这里就得这么写了(即调用BouncyCastle组件实现)

		// Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM, "BC");
		Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM); // 实例化Cipher对象，它用于完成实际的加密操作
		cipher.init(Cipher.ENCRYPT_MODE, k); // 初始化Cipher对象，设置为加密模式
		return Base64.encodeBase64String(cipher.doFinal(data.getBytes())); // 执行加密操作。加密后的结果通常都会用Base64编码进行传输
	}

	/**
	 * 078 解密数据 079
	 * 
	 * @param data
	 *            待解密数据 080
	 * @param key
	 *            密钥 081
	 * @return 解密后的数据 082
	 * */
	public static byte[] decrypt(byte[] data, byte[] key) throws Exception {
		// String keys = parseByte2HexStr(key);
		Key k = toKey(key);
		// Key k = toKey(Base64.decodeBase64(keys));
		Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
		cipher.init(Cipher.DECRYPT_MODE, k); // 初始化Cipher对象，设置为解密模式
		// String datas = parseByte2HexStr(data);
		return cipher.doFinal(data); // 执行解密操作
	}

	public static String parseByte2HexStr(byte buf[]) {
		StringBuffer sb = new StringBuffer();
		for (int i = 0; i < buf.length; i++) {
			String hex = Integer.toHexString(buf[i] & 0xFF);
			if (hex.length() == 1) {
				hex = '0' + hex;
			}
			sb.append(hex.toUpperCase());
		}
		return sb.toString();
	}

	public static void main(String[] args) throws Exception {
		String source = "站在云端，敲下键盘，望着通往世界另一头的那扇窗，只为做那读懂0和1的人。。";
		System.out.println("原文：" + source);

		String key = initkey();
		System.out.println("密钥：" + key);

		String encryptData = encrypt(source, key);
		System.out.println("加密：" + encryptData);

		// String decryptData = decrypt(encryptData, key);
		// System.out.println("解密: " + decryptData);
	}

	public static byte[] decryptAES128(byte[] paramArrayOfByte1,
			byte[] paramArrayOfByte2) throws Exception {
		SecretKeySpec localSecretKeySpec = new SecretKeySpec(paramArrayOfByte1,
				"AES");
		Cipher localCipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
		localCipher.init(2, localSecretKeySpec);
		return localCipher.doFinal(paramArrayOfByte2);
	}

	public static byte[] decryptAESCBC128_test(byte[] paramArrayOfByte1,
			byte[] paramArrayOfByte2, byte[] paramArrayOfByte3)
			throws Exception {
		SecretKeySpec localSecretKeySpec = new SecretKeySpec(paramArrayOfByte1,
				"AES");
		IvParameterSpec localIvParameterSpec = new IvParameterSpec(
				paramArrayOfByte2);
		Cipher localCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
		localCipher.init(2, localSecretKeySpec, localIvParameterSpec);
		return localCipher.doFinal(paramArrayOfByte3);
	}

}
